unit AcroShellHook;

interface
uses
  Windows,Messages,Forms,Classes;

type
  TShellHookMessageNotify=procedure(var Msg:TMessage) of object;
  
  TAcroShellHook=class
  private
    FWindowHandle:THandle;
    FMsgID:Cardinal;
    FOnShellHookMessage:TShellHookMessageNotify;
    procedure AcroWnd(var Msg:TMessage);
    procedure SetOnMessage(const Value: TShellHookMessageNotify);
  public
    constructor Create;
    destructor Destroy;override;
    procedure Hook;
    procedure UnHook;
    property OnShellHookMessage:TShellHookMessageNotify read FOnShellHookMessage write SetOnMessage;
  end;

var
  AcroShellHookStorage:TAcroShellHook;

implementation

  function RegisterShellHook(HWND,nAction: LongWord): Integer; stdcall;external 'Shell32.dll';
  function RegisterShellHookWindow(HWND: LongWord): Integer; stdcall;external 'User32.dll';


procedure TAcroShellHook.AcroWnd(var Msg: TMessage);
begin
//only monitor application main window
  if Msg.Msg=FMsgID then
  begin
    if Assigned(FOnShellHookMessage) then FOnShellHookMessage(Msg);
  end
  else
    Msg.Result:=DefWindowProc(FWindowHandle,Msg.Msg,Msg.WParam,Msg.lParam);
end;

constructor TAcroShellHook.Create;
begin
  inherited;
  FWindowHandle:=0;
end;

destructor TAcroShellHook.Destroy;
begin
  UnHook;
  inherited;
end;

procedure TAcroShellHook.Hook;
begin
  if FWindowHandle=0 then
  begin
    FWindowHandle:=AllocateHWnd(AcroWnd);
    FMsgID:=RegisterWindowMessage('SHELLHOOK');
    RegisterShellHookWindow(FWindowHandle);
  end;
end;

procedure TAcroShellHook.SetOnMessage(const Value: TShellHookMessageNotify);
begin
  FOnShellHookMessage := Value;
end;

procedure TAcroShellHook.UnHook;
begin
  if FWindowHandle>0 then
  begin
    DeallocateHWnd(FWindowHandle);
    FWindowHandle:=0;
  end;
end;

initialization
  AcroShellHookStorage:=TAcroShellHook.Create;
finalization
  AcroShellHookStorage.Free;
end.
